﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Pg.BioMedics.SDR.Caching.Linq
{
    internal class DistributedCacheQueryProvider<T> : IQueryProvider
    {
        #region Fields

        private DistributedCachingStrategy<T> cachingStrategy;

        #endregion

        #region Constructors

        internal DistributedCacheQueryProvider(DistributedCachingStrategy<T> cachingStrategy)
        {
            this.cachingStrategy = cachingStrategy;
        }

        #endregion

        #region IQueryProvider Members

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            if (typeof(TElement) == typeof(T))
                return new DistributedCacheQueryable<T>(this.cachingStrategy, expression) as IQueryable<TElement>;
            else
                throw new InvalidOperationException(String.Format("Only {0} type is supported by this query provider", typeof(T)));
        }

        /// <summary>
        /// Create a new object implementing IOueriable for the given expression
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public IQueryable CreateQuery(Expression expression)
        {
            Type elementType = typeof(T);
            try
            {
                return (IQueryable)Activator.CreateInstance(typeof(DistributedCacheQueryable<>).MakeGenericType(elementType), new object[] { this.cachingStrategy, expression });
            }
            catch (System.Reflection.TargetInvocationException tie)
            {
                throw tie.InnerException;
            }
        }

        public TResult Execute<TResult>(Expression expression)
        {
            IEnumerable<string[]> parameters = ExpressionProcessor.ProcessExpression<T>(expression);

            IList<T> result = new List<T>();
            foreach (string[] tags in parameters)
                foreach (T item in this.cachingStrategy.Get(tags))
                    result.Add(item);

            return (TResult)result;
        }

        public object Execute(Expression expression)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
